package org.summerframework.component.mybites.redislock;

import org.summerframework.component.mybites.annotation.Synchronized;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.annotation.Order;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

import javax.annotation.Resource;
import java.lang.reflect.Method;

/**
 * @author 石超
 * @version v1.0.0
 */
@Aspect
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SynchronizedInterceptor implements Ordered, MethodInterceptor {
    @Resource
    private Locker locker;

    private DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();

    private ExpressionParser parser = new SpelExpressionParser();

    @Around(value = "@annotation(org.summerframework.component.mybites.annotation.Synchronized)")
    public Object aSynchronized(ProceedingJoinPoint joinPoint) throws
            Throwable {
        //获取切面方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Synchronized aSynchronized = AnnotationUtils.findAnnotation(method, Synchronized.class);
        //获取方法的形参名称
        String[] params = discoverer.getParameterNames(method);
        //设置解析spel所需的数据上下文
        EvaluationContext context = new StandardEvaluationContext();

        if (params != null) {
            //获取方法的实际参数值
            Object[] arguments = joinPoint.getArgs();

            for (int len = 0; len < params.length; len++) {
                context.setVariable(params[len], arguments[len]);
            }

            if (StringUtils.isBlank(aSynchronized.lockKey())) {
                throw new IllegalArgumentException(String.format("%s @Synchronized lockKey is blank", method.toString()));
            }
        }

        //解析表达式并获取spel的值
        Expression expression = parser.parseExpression(aSynchronized.lockKey());
        Object theValue = expression.getValue(context);

        if (theValue == null) {
            return joinPoint.proceed();
        }

        final String key = String.valueOf(theValue);

        try {
            acquire(key, aSynchronized.timeout());
            return joinPoint.proceed();
        } finally {
            release(key);
        }
    }

    /**
     * 获取锁
     *
     * @param key     锁名称  key与string互斥,  String优先
     * @param timeout 超时
     */
    private void acquire(String key, int timeout) {
        locker.lock(key, timeout);
    }

    /**
     * 释放锁
     *
     * @param key 锁名称  key与string互斥,  String优先
     */
    public void release(String key) {
        locker.unlock(key);
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        return methodInvocation.proceed();
    }
}
